import {h, Component, findDOMNode, render} from 'preact'
import axios from 'axios';
import {dataS, optionData, componentData} from '@/index.js';
import '../../style/index.css'
import * as util from "../../utils/index";

class Framework extends Component {
    _searchInputRef;

    constructor(options) {
        super(options);
        //保留对象引用
        componentData[options.elem] = this;
        //初始化state数据
        this.setState({
            value: this.props.initValue || '',
            showName: this.props.initValue || '', // 显示的name值
            _value: this.props.initValue || '', // 实际取值
            remote: true,
            disposable: true,
            loading: false,
            show: this.props.hasInitShow || false,
            page: 1,
            totalCount: 0,
            data: [],
            itemClick: false,
        });
        this.pageCount = 0;
        this.copyData = this.props.data || [];
        this.searchCb = 0;
        this.inputSearchOver = true;
        this._value = this.props.initValue || '';
    }

    /**
     * 处理生命周期
     * @param e
     */
    handleComposition(e) {
        let type = e.type;
        if (type === 'compositionstart') {
            this.inputSearchOver = false;
            this.searchCb && clearTimeout(this.searchCb);
        } else if (type === 'compositionend') {
            this.inputSearchOver = true;
            this._inputChange(e);
        } else {
            this._inputChange(e);
        }
    }

    /**
     * 处理组件内点击事件
     * @param e
     */
    handleClickOutside(e) {
        if (!this._selfComponent.contains(e.target)) {
            dataS[this.props.elem].closed();
        }
    }

    componentWillUnmount() {
        document.removeEventListener('click', this.handleClickOutside.bind(this));
    }

    /**
     * 组件加载完毕回调
     */
    componentDidMount() {
        let input = this.base.querySelector('.select-input-input');
        if (input) {
            input.addEventListener('compositionstart', this.handleComposition.bind(this));
            input.addEventListener('compositionupdate', this.handleComposition.bind(this));
            input.addEventListener('compositionend', this.handleComposition.bind(this));
            input.addEventListener('input', this._inputChange.bind(this));
            if (this.props.inputClickShow) input.addEventListener('click', this._iconShow.bind(this));
        }
        document.addEventListener('click', this.handleClickOutside.bind(this));
        this.props.done && this.props.done()
    }

    //此时页面又被重新渲染了
    componentDidUpdate() {
        if (this.callback) {
            this.callback = false;
            let done = this.props.done();
            if (util.isFunction(done)) {
                done(this.state.value, this.copyData || []);
            }
        }
    }

    //组件将要接收新属性
    componentWillReceiveProps(props) {
        console.log(props)
    }

    /**
     * 输入框聚焦
     */
    focus() {
        this._searchInputRef && this._searchInputRef.focus();
    }

    /**
     * 输入框失焦
     */
    blur() {
        this._searchInputRef && this._searchInputRef.blur();
    }

    /**
     * input实时输入事件
     * @param e
     * @returns {boolean}
     * @private
     */
    _inputChange(e) {
        let v = e.target.value;
        //if (v === this._value && this._value !== '') return false;
        if (!this.props.hasCut && e.inputType === 'insertFromPaste') return false;
        this.setState({show: false});
        this.searchCb && clearTimeout(this.searchCb);
        this.setState({
            showName: v
        })
        if (this.inputSearchOver) {
            this._value = v;
            this.searchCb = setTimeout(() => {
                this.callback = true;
                this.setState({value: this._value, show: true, itemClick: false, remote: true, page: 1})
                if (util.isFunction(this.props.onInput)) {
                    this.props.onInput(this._value, e);
                }
            }, this.props.delay);
        }
    }

    /**
     * 响应键盘事件
     * @param e
     * @private
     */
    _inputKeyDown(e) {
        if (parseInt(e.keyCode) === 13
            && this.props.remoteEvent === 'keydown'
            && (this.props.pageRemote || this.props.remoteSearch)) {
            // 执行远程搜索
            this.remoteData(this.state.page, true)
        }
    }

    /**
     * 点击选择
     * @param item
     * @private
     */
    _optionClick(item) {
        if (this.props.onClick && util.isFunction(this.props.onClick)) {
            this.props.onClick(item)
        }
        if (this.props.clickClose) {
            this._iconShow()
        }
        this.setState({
            value: item[this.props.prop[this.props.showProp]],
            showName: item[this.props.prop[this.props.showProp]],
            _value: item[this.props.prop.value],
            itemClick: true
        }, () => {
            // 点击后由于value需要重载数据
            if (this.props.paging) {
                const _page = 1;
                this._changePage(_page);
                this.props.pageRemote && this.remoteData(_page, true);
            }
        })
    }

    /**
     * 展开隐藏
     * @private
     */
    _iconShow() {
        this.setState({
            show: !this.state.show
        }, () => {
            let _callbackName = this.state.show ? 'show' : 'hide';
            let callback = this.props[_callbackName] || null;
            if (callback && util.isFunction(callback)) {
                callback();
            }
            if (this.state.show) {
                this.focus();
            }
        })
    }

    /**
     * 更改分页
     * @param page
     * @private
     */
    _changePage(page) {
        this.setState({
            page: page
        })
    }

    /**
     * 上一页
     * @private
     */
    _prevPage(pageCount = this.pageCount) {
        let _page = this.state.page;
        if (_page <= 1) {
            return false;
        }
        _page = _page - 1;
        this._changePage(_page);
        this.props.pageRemote && this.remoteData(_page, true);
    }

    /**
     * 下一页
     * @private
     */
    _nextPage(pageCount = this.pageCount) {
        let _page = this.state.page;
        if (_page >= pageCount) {
            return;
        }
        _page = _page + 1;
        this._changePage(_page);
        this.props.pageRemote && this.remoteData(_page, true);
    }

    /**
     * 远程加载数据
     * @param page
     * @param force
     */
    remoteData(page = this.state.page, force = false) {
        if (this.state.remote || force) {
            this.callback = false;
            this.setState({loading: true, remote: false});
            this.blur();
            this.props.remoteMethod(this.state.value, (result, totalCount = 1) => {
                setTimeout(() => {
                    if (util.isFunction(this.props.parseData)) {
                        result = this.props.parseData(result);
                    }
                    //回调后可以重新聚焦
                    this.focus();
                    this.callback = true;
                    this.copyData = result;
                    this.setState({data: result, loading: false, totalCount});
                }, 10);
            }, page);
        }
    }

    /**
     * 一次性远程加载数据
     * @param url
     * @param method
     * @param params
     */
    getData(url, method = 'get', params = {}) {
        if (this.state.disposable) {
            this.setState({disposable: false})
            axios[method](url, method === 'get' ? {params: params} : params).then((response) => {
                let ret = response.data;
                if (ret[this.props.statusCode] === this.props.statusOK) {
                    let _data = ret[this.props.statusData] || []
                    if (util.isFunction(this.props.parseData)) {
                        _data = this.props.parseData(_data);
                    }
                    this.setState({data: _data})
                    this.copyData = _data;
                }
            }).catch(function (error) {
                // handle error
                console.log(error);
            });
        }
    }

    /**
     * 获取value
     * @returns {{isSelect: boolean, value: *}|*}
     */
    getValue() {
        if (this.props.invisibleMode) {
            let _value = {value: this.state._value, isSelect: false}
            let _data = this.state.data || []
            _data.forEach(key => {
                if (this.state._value === _data[key].value) {
                    _value.isSelect = true;
                }
            })
            return _value;
        }
        return this.state._value
    }

    /**
     * 渲染组件
     */
    render(config, state) {

        let {
            hasSelectIcon,
            localSearch,
            pageRemote,
            remoteSearch,
            filterMethod,
            prop,
            isPureSelectMode,
            ignoreCase
        } = config

        if (isPureSelectMode) hasSelectIcon = true; // 强制点击显示隐藏模式
        // 一次性远程数据加载到本地
        let arr = this.state.data

        // 如果传递data优先使用data渲染页面
        if (config.hasData && this.state.disposable) {
            this.setState({disposable: false, data: config.data})
            this.copyData = config.data;
        }

        // 一次性加载远程数据到本地data
        if (config.url && config.data.length <= 0
            && !(remoteSearch || pageRemote)
        ) {
            this.getData(config.url, config.method, config.params)
        }

        //远程分页 或者 远程搜索
        if (pageRemote || remoteSearch) {
            this.remoteData();
        }

        // 本地搜索过滤
        if (localSearch && !(remoteSearch || pageRemote)) {
            const _filter = (item, index) => {
                return filterMethod(this.state.value, item, index, prop, ignoreCase);
            }
            if (!this.state.itemClick && this.state.value !== config.initValue) {
                arr = arr.filter(_filter);
            }
        }

        // 处理分页
        let paging = '';
        if (config.paging) {
            //计算总页码
            let pageCount = config.pageRemote ? Math.ceil(this.state.totalCount / config.pageSize) : Math.floor((arr.length - 1) / config.pageSize) + 1;
            pageCount <= 0 && (pageCount = 1);

            let _page = this.state.page;
            if (_page > pageCount) {
                _page = pageCount;
            }
            if (pageCount > 0 && _page <= 0) {
                _page = 1;
            }
            if (!config.pageRemote) {
                // 前端分页
                let start = (_page - 1) * config.pageSize;
                let end = start + config.pageSize;
                arr = arr.slice(start, end);
            }
            const disabledClass = 'select-input-no-drop';
            let prevClass = {}, nextClass = {};
            _page <= 1 && (prevClass = disabledClass);
            _page === pageCount && (nextClass = disabledClass);

            this.state.page !== _page && this._changePage(_page);
            this.pageCount = pageCount;
            paging = (
                <div className="select-input-paging">
                    <span className={prevClass} onClick={this._prevPage.bind(this, pageCount)}>上一页</span>
                    <span>{this.state.page} / {pageCount}</span>
                    <span className={nextClass} onClick={this._nextPage.bind(this, pageCount)}>下一页</span>
                </div>
            )
        }

        let _class = arr.length <= 0 ? 'dis' : (this.state.show ? '' : 'dis');
        _class = 'select-input-body ' + _class

        // 处理数据渲染
        const renderOption = item => {
            return (
                <li className="select-input-option-content"
                    onClick={this._optionClick.bind(this, item)}
                    data-value={item[config.prop.value]}>{item[config.prop.name]}</li>
            )
        }
        arr = arr.map(renderOption);

        let _icon = '';
        if (hasSelectIcon) {
            let _iconClass = 'select-input-icon ' + (this.state.show ? 'select-input-icon-expand' : '')
            _icon = (<i className={_iconClass} onClick={this._iconShow.bind(this)}/>);
        }

        let _load = '';
        if (this.state.loading) {
            _load = (<div className="select-input-loading">
                <span class="select-input-loader"></span>
            </div>)
        }
        let style = '';
        if (config.height) {
            style += 'max-height: ' + config.height;
        }
        return <div className="select-input">
            <div className="select-input-content" ref={(_selfComponent) => this._selfComponent = _selfComponent}>
                <div className="select-input-container">
                    <input className="select-input-input" name={config.name}
                           autoComplete="off"
                           readOnly={isPureSelectMode}
                           value={this.state.showName}
                           placeholder={config.placeholder}
                           lay-filter={config.layFilter}
                           lay-verify={config.layVerify}
                           lay-vertype={config.layVerType}
                           lay-reqtext={config.layReqText}
                           ref={(input) => this._searchInputRef = input}
                           onKeyDown={this._inputKeyDown.bind(this)}
                    />
                    {_icon}
                </div>
                <div className={_class}>
                    <div className="scroll-body" style={style}>
                        <ul className="select-input-option">
                            {arr}
                        </ul>
                        {_load}
                    </div>
                    {paging}
                </div>
            </div>
        </div>
    }
}

export default Framework;
